/*******************************************************************************
 * SDP Project AUT 2012
 * 
 *                ***********Driving Assistant************
 * Team:
 * Gisela, Deidre, Brijesh, Robert
 * 
 * This class sets up the main frame which houses the panels needed to make up
 * the UI components.
 * 
 * @version 1.0
 * 
 * Copyright (c) 2012 by DrivingAssistant Team, Inc., All Rights Reserved.
 * 
 ******************************************************************************/
package com.drivingAssistant.gui;

import com.drivingAssistant.model.ArduinoCommunicator;
import com.drivingAssistant.model.SoundOff;
import com.drivingAssistant.model.OpenDialogWindow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.DefaultCaret;

public class DrivingAssistantGUI extends JFrame {
    
    // constants
    private static final String beep1Clip = "./sound/beep-01.wav";
    private static final String beep2Clip = "./sound/beep-02.wav";
    private static final String beep3Clip = "./sound/beep-03.wav";
    private static final String beep4Clip = "./sound/beep-04.wav";
    private static final String beep5Clip = "./sound/beep-05.wav";
    private static final String lazerClip = "./sound/lazer.wav";
    private static final String hornClip = "./sound/horn.wav";
    private static final String redAlertClip = "./sound/redalert.wav";
    private static final int UI_WIDTH = 622;    // Pixels.
    private static final int UI_HEIGHT = 486;
    final static int LEVEL_ONE = 4;
    final static int LEVEL_TWO = 1;
    final static int LEVEL_THREE = 0;
    
    Color colour;
    
    ArduinoCommunicator ac = null;
    OpenDialogWindow user_guide = null;
    OpenDialogWindow about_file = null;
    SoundOff soundOff = null;
    
    public JTextArea distanceTextArea = null;
    JPanel outputPanel, logoPanel, labelPanel, 
            leftPanel, rightPanel, middlePanel,
            topRangePanel, bottomRangePanel, leftRangePanel,
            rightRangePanel, topOutputPanel, bottomOutputPanel, 
            leftOutputPanel, rightOutputPanel;
    JPanel spaceLabel, spaceLabel2;
    JLabel comLabel = null;
    public JComboBox comBox = null;
    JMenuBar menuBar = null;
    JMenu optionMenu, connectionMenu, soundMenu;
    JMenuItem exit, userGuide, aboutFile, connect, disconnect;
    public JRadioButtonMenuItem beep1, beep2, beep3, beep4, 
            beep5, lazer, horn, redAlert;
    ButtonGroup buttonGroup = null;
    
    JScrollPane scrollPane;
    public JSpinner rangeTxt;
    SpinnerModel model = null;
    DefaultCaret caret;
    public int initialValue = 20;
    
    /**
     * 
     * @throws LineUnavailableException 
     */
    public DrivingAssistantGUI() throws LineUnavailableException {
        setPreferredSize(new Dimension(UI_WIDTH, UI_HEIGHT));
        setResizable(false);
        setLayout(new BorderLayout());
        setTitle("Driving Assistant");
        
        soundOff = new SoundOff();
        user_guide = new OpenDialogWindow();
        about_file = new OpenDialogWindow();
        colour = new Color(210, 105, 30, 255); // orange
        distanceTextArea = new JTextArea();
        buttonGroup = new ButtonGroup();
        logoPanel = new Logo();
        labelPanel = new Distance();
        leftPanel = new JPanel();
        rightPanel = new JPanel();
        middlePanel = new JPanel();
        topRangePanel = new JPanel();
        bottomRangePanel = new JPanel();
        leftRangePanel = new JPanel();
        rightRangePanel = new JPanel();
        topOutputPanel = new JPanel();
        bottomOutputPanel = new JPanel();
        leftOutputPanel = new JPanel();
        rightOutputPanel = new JPanel();
        leftPanel.setOpaque(false);
        rightPanel.setOpaque(false);
        middlePanel.setOpaque(false);
        topRangePanel.setOpaque(false);
        bottomRangePanel.setOpaque(false);
        leftRangePanel.setOpaque(false);
        rightRangePanel.setOpaque(false);
        topOutputPanel.setOpaque(false);
        bottomOutputPanel.setOpaque(false);
        leftOutputPanel.setOpaque(false);
        rightOutputPanel.setOpaque(false);
        spaceLabel = new JPanel();
        spaceLabel2 = new JPanel();
        comLabel = new JLabel("Communication Port: ");
        comBox = new JComboBox();
        menuBar = new JMenuBar();
        optionMenu = new JMenu("Options");
        connectionMenu = new JMenu("Connect");
        exit = new JMenuItem("Exit");
        userGuide = new JMenuItem("User Guide");
        aboutFile = new JMenuItem("About Driving Assistant");
        connect = new JMenuItem("Connect");
        disconnect = new JMenuItem("Disconnect");
        setUpMenuBar();
        setUpPanels();
        ac.searchForPorts();
        setInitialValue();
    }

    /**
     * 
     */
    private void setUpMenuBar() {
        
        menuBar = new JMenuBar();
        optionMenu = new JMenu("Options");
        
        exit = new JMenuItem("Exit");
        exit.setMnemonic('E');
        exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,
                                                       InputEvent.CTRL_MASK));
        exit.addActionListener(new AbstractAction("Exit") {

            @Override
            public void actionPerformed(ActionEvent e) {
                Object[] options = {"Quit", "Continue"};
                int choice = JOptionPane.showOptionDialog(
                        rootPane,
                        "Please confirm option", 
                        "Options",
                        JOptionPane.YES_NO_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE,
                        null,
                        options,
                        options[0]);
                if (choice == 0) {
                    if (ac != null) {
                        ac.disconnect();
                    }
                    System.exit(0);
                }
            }
        });
        
        userGuide = new JMenuItem("User Guide");
        userGuide.setMnemonic('U');
        userGuide.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U,
                                                       InputEvent.CTRL_MASK));
        userGuide.addActionListener(new AbstractAction("User Guide") {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(
                        null,
                        user_guide.openDialog("userGuide"),
                        "Driving Assistant User Guide",
                        JOptionPane.PLAIN_MESSAGE);
            }
        });
        
        aboutFile = new JMenuItem("About Driving Assistant");
        aboutFile.setMnemonic('A');
        aboutFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                       InputEvent.CTRL_MASK));
        aboutFile.addActionListener(new AbstractAction("About Driving Assistant") {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(
                        null,
                        about_file.openDialog("aboutFile"),
                        "About Driving Assistant",
                        JOptionPane.PLAIN_MESSAGE);
            }
        });
        
        
        optionMenu.setMnemonic(KeyEvent.VK_O);
        optionMenu.setToolTipText("click here to "
                + "view options menu");
        optionMenu.add(userGuide);
        optionMenu.add(aboutFile);
        optionMenu.addSeparator();
        optionMenu.add(exit);
        
        comLabel.setToolTipText("click drop down arrow "
                + "to view available ports");
        
        
        connect = new JMenuItem("Connect");
        connect.setMnemonic('C');
        connect.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
                                                       InputEvent.CTRL_MASK));
        connect.addActionListener(new AbstractAction("Connect") {

            @Override
            public void actionPerformed(ActionEvent e) {
                ac.connect();
                if (ac.getConnected() == true) {
                    if (ac.initIOStream() == true) {
                        ac.initListener();
                    }
                }
            }
        });
        
        disconnect = new JMenuItem("DisConnect");
        disconnect.setMnemonic('D');
        disconnect.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D,
                                                       InputEvent.CTRL_MASK));
        disconnect.addActionListener(new AbstractAction("DisConnect") {

            @Override
            public void actionPerformed(ActionEvent e) {
                ac.disconnect();
            }
        });
        
        connectionMenu.setMnemonic(KeyEvent.VK_C);
        connectionMenu.setToolTipText("click here to connect to or "
                + "disconnect from comm ports");
        connectionMenu.add(connect);
        connectionMenu.add(disconnect);
        
        comBox = new JComboBox();
        comBox.setPreferredSize(new Dimension(25, 25));
        
        soundMenu = new JMenu("Sounds");
        soundMenu.setMnemonic(KeyEvent.VK_S);
        soundMenu.setToolTipText("click to view "
                + "sound selection");
        beep1 = new JRadioButtonMenuItem("Beep 1");
        beep1.setEnabled(true); // default sound
        beep1.addActionListener(new AbstractAction("Beep 1") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (beep1.isSelected()) {
                    try {
                        soundOff.setClip(beep1Clip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        beep2 = new JRadioButtonMenuItem("Beep 2");
        beep2.addActionListener(new AbstractAction("Beep 2") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (beep2.isSelected()) {
                    try {
                        soundOff.setClip(beep2Clip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        beep3 = new JRadioButtonMenuItem("Beep 3");
        beep3.addActionListener(new AbstractAction("Beep 3") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (beep3.isSelected()) {
                    try {
                        soundOff.setClip(beep3Clip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        beep4 = new JRadioButtonMenuItem("Beep 4");
        beep4.addActionListener(new AbstractAction("Beep 4") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (beep4.isSelected()) {
                    try {
                        soundOff.setClip(beep4Clip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        beep5 = new JRadioButtonMenuItem("Beep 5");
        beep5.addActionListener(new AbstractAction("Beep 5") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (beep5.isSelected()) {
                    try {
                        soundOff.setClip(beep5Clip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        lazer = new JRadioButtonMenuItem("Lazer");
        lazer.addActionListener(new AbstractAction("Lazer") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (lazer.isSelected()) {
                    try {
                        soundOff.setClip(lazerClip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        horn = new JRadioButtonMenuItem("Horn");
        horn.addActionListener(new AbstractAction("Horn") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (horn.isSelected()) {
                    try {
                        soundOff.setClip(hornClip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        redAlert = new JRadioButtonMenuItem("Red Alert");
        redAlert.addActionListener(new AbstractAction("Red Alert") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (redAlert.isSelected()) {
                    try {
                        soundOff.setClip(redAlertClip);
                        soundOff.playClip(LEVEL_THREE);
                    } catch (LineUnavailableException ex) {
                        Logger.getLogger(DrivingAssistantGUI.class.getName())
                                .log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        buttonGroup.add(beep1);
        buttonGroup.add(beep2);
        buttonGroup.add(beep3);
        buttonGroup.add(beep4);
        buttonGroup.add(beep5);
        buttonGroup.add(lazer);
        buttonGroup.add(horn);
        buttonGroup.add(redAlert);
        soundMenu.add(beep1);
        soundMenu.add(beep2);
        soundMenu.add(beep3);
        soundMenu.add(beep4);
        soundMenu.add(beep5);
        soundMenu.add(lazer);
        soundMenu.add(horn);
        soundMenu.add(redAlert);
        
        this.setJMenuBar(menuBar);
        
        menuBar.add(optionMenu);
        menuBar.add(connectionMenu);
        menuBar.add(soundMenu);
        menuBar.add(spaceLabel2);
        menuBar.add(comLabel);
        menuBar.add(comBox);
        menuBar.add(spaceLabel);
        
        
    }
    
    /**
     * 
     * @throws LineUnavailableException 
     */
    private void setUpPanels() throws LineUnavailableException {
        ac = new ArduinoCommunicator(this);
        getContentPane().setBackground(colour);
        
        // set limit for jspinner to max 105 and min 15
        int min = 15;
        int max = 105;
        int step = 5;
        model = new SpinnerNumberModel(initialValue, min, max, step);
        rangeTxt = new JSpinner(model);
        JFormattedTextField formatTextField = ((JSpinner.DefaultEditor)rangeTxt
                .getEditor()).getTextField();
        formatTextField.setEditable(false);
        rangeTxt.setFont(new Font("Times New Roman", 1, 42));
        rangeTxt.setToolTipText("Current Detection Range");
        
        distanceTextArea.setEditable(false);
        distanceTextArea.setFont(new Font("Times New Roman", 1, 24));
        
        scrollPane = new JScrollPane(distanceTextArea);
        scrollPane.setToolTipText("Display distance readings");
        scrollPane.setAlignmentX(LEFT_ALIGNMENT);
        scrollPane.getHorizontalScrollBar().setEnabled(false);
        scrollPane.getHorizontalScrollBar().setVisibleAmount(10);
        scrollPane.getVerticalScrollBar().addAdjustmentListener(
                new AdjustmentListener() {

            @Override
            public void adjustmentValueChanged(AdjustmentEvent e) {
                distanceTextArea.select(distanceTextArea.getCaretPosition()*24, 0);
            }
        });
        
        labelPanel.setLayout(new GridLayout(1,3, 10, 10));
        // put range text spinner in position
        leftPanel.setLayout(new BorderLayout());
        topRangePanel.setPreferredSize(new Dimension(50,150));
        bottomRangePanel.setPreferredSize(new Dimension(50,100));
        leftRangePanel.setPreferredSize(new Dimension(90,50));
        rightRangePanel.setPreferredSize(new Dimension(130,50));
        leftPanel.add(rangeTxt, BorderLayout.CENTER);
        leftPanel.add(topRangePanel, BorderLayout.NORTH);
        leftPanel.add(bottomRangePanel, BorderLayout.SOUTH);
        leftPanel.add(rightRangePanel, BorderLayout.EAST);
        leftPanel.add(leftRangePanel, BorderLayout.WEST);
        // put output text area in position
        rightPanel.setLayout(new BorderLayout());
        topOutputPanel.setPreferredSize(new Dimension(50,150));
        bottomOutputPanel.setPreferredSize(new Dimension(30,50));
        leftOutputPanel.setPreferredSize(new Dimension(0,50));
        rightOutputPanel.setPreferredSize(new Dimension(50,50));
        rightPanel.add(scrollPane, BorderLayout.CENTER);
        rightPanel.add(topOutputPanel, BorderLayout.NORTH);
        rightPanel.add(bottomOutputPanel, BorderLayout.SOUTH);
        rightPanel.add(rightOutputPanel, BorderLayout.EAST);
        rightPanel.add(leftOutputPanel, BorderLayout.WEST);
        
        labelPanel.add(leftPanel);
        labelPanel.add(rightPanel);
        
        add(logoPanel, BorderLayout.NORTH);
        add(labelPanel, BorderLayout.CENTER);
    }
    
    /**
     * Get the sound which has been enabled
     * 
     * @return selected sound
     */
    public synchronized String getSelectedSound() {
        String selectedSound = "";
        if (beep1.isSelected()) {
            selectedSound = beep1Clip;
        }
        if (beep2.isSelected()) {
            selectedSound = beep2Clip;
        }
        if (beep3.isSelected()) {
            selectedSound = beep3Clip;
        }
        if (beep4.isSelected()) {
            selectedSound = beep4Clip;
        }
        if (beep5.isSelected()) {
            selectedSound = beep5Clip;
        }
        if (lazer.isSelected()) {
            selectedSound = lazerClip;
        }
        if (horn.isSelected()) {
            selectedSound = hornClip;
        }
        if (redAlert.isSelected()) {
            selectedSound = redAlertClip;
        }
        return selectedSound;
    }
    
    /**
     * Set the range value
     */
    private void setInitialValue() {
        this.initialValue = (Integer)rangeTxt.getValue();
    }
    
    /**
     * Get the range value set by user
     * 
     * @return initialValue
     */
    public synchronized int getInitialValue() {
        this.initialValue = (Integer)rangeTxt.getValue();
        return this.initialValue;
    }
    
}

